package application;



import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.logging.Logger;

import ui.TimeWorkerListModel;
import workers.ServerWorker;
import workers.TimedWorker;


public class Server implements Runnable{

	public static final String loggerName = "mainLogger";
	
	private final ServerSocket serverSocket;
	private final ExecutorService pool;
	private File fileRoot;
	private boolean flag = true;
	private int poolSize;

	public static final int PORT = 56765;
	
	private TimeWorkerListModel workers;
	
	//starts as a concurrent fixed size thread pool executor service
	public Server(int port, int poolSize , File root , TimeWorkerListModel workers)
	throws IOException {
		serverSocket = new ServerSocket(port);
		pool = Executors.newFixedThreadPool(poolSize);
		fileRoot = root; 
		this.workers = workers;
		this.poolSize = poolSize;
		Logger.getLogger(Server.loggerName).info( getDescription() );
	}
	
	//starts as a sequential executor service
	public Server( int port , File root, TimeWorkerListModel workers)
	throws IOException {
		serverSocket = new ServerSocket(port);
		//it's equivalent to have a fixed pool thread with one thread to having a
		//sequential one thread only executor.. only that this executor can be 
		//reconfigured to hold more threads later on
		pool = Executors.newSingleThreadExecutor();
		fileRoot = root;
		this.workers = workers;
		this.poolSize = 1;
		Logger.getLogger(Server.loggerName).info(getDescription());
	}

	//starts a server witha  given pool thread and a server socket
	public Server( ExecutorService threadPool , ServerSocket  ss , File root , TimeWorkerListModel workers )
	throws IOException {
		serverSocket = ss;
		pool = threadPool; //Executors.newSingleThreadExecutor();
		poolSize = 0;
		fileRoot = root;
		this.workers = workers;
		Logger.getLogger(Server.loggerName).info(getDescription());
	}

	
	public void stop(){
		flag = false;
		try {
			serverSocket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void run() { // run the service

		int count = 0;
		try {
			flag = true;
			while(flag)
			{
				Socket cliente = serverSocket.accept();
				ServerWorker command = new ServerWorker(cliente, fileRoot, workers);
				pool.submit( command , (TimedWorker) command );
				workers.add( command );
				count ++;
			}
			pool.shutdown();
		} catch (IOException ex) {
			pool.shutdown();
			Logger.getLogger(Server.loggerName).info("server socket closed. shutting down pool of threads");
		}
	}
	public int getPoolSize() {
		return poolSize;
	}
	
	public File getFileRoot() {
		return fileRoot;
	}

	public String getDescription() {
		String description = "Server ExecutorService is " + pool.getClass().getName() ;
		if( pool instanceof ThreadPoolExecutor ){
			description += " with MAX_POOL_SIZE = " + ((ThreadPoolExecutor) pool).getMaximumPoolSize();
			description += " and POOL_SIZE = " + ((ThreadPoolExecutor) pool).getPoolSize();
		}
		else{
			description += " AKA single thread executor";
		}
		return description;
	}
}
